/**
 * 
 */
package se.cirrus.base.com;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import se.cirrus.base.error.CommunicationException;
import se.cirrus.base.error.InvalidStateException;

/**
 * @author Winquman
 *
 */
public class BasicIPListener implements Listener {

	private int port;
	
	private int state;
	
	private ServerSocket socket;
	
	private Controller controller;
	
	Logger log;
	
	/**
	 * 
	 */
	public BasicIPListener(int port, Controller controller) {
		log = LogManager.getLogManager().getLogger("ALL");
		
		log.fine("Initializing a listerner...");
		this.port = port;
		state = CommunicationState.CLOSED;
		this.controller = controller;
	}

	/* (non-Javadoc)
	 * @see se.cirrus.base.com.Listener#getStatus()
	 */
	@Override
	public int getStatus() {
		
		return state;
	}

	/* (non-Javadoc)
	 * @see se.cirrus.base.com.Listener#okay()
	 */
	@Override
	public boolean ready() {
		
		return (state != CommunicationState.ERROR && state != CommunicationState.UNINITIALIZED);
	}

	/* (non-Javadoc)
	 * @see se.cirrus.base.com.Listener#open()
	 */
	@Override
	public void open() throws InvalidStateException, CommunicationException {

		log.fine("Opening listener " + this + "for connections.");
		try {
			socket = new ServerSocket(port);
			log.fine("Successfully opened port!");
		} catch (IOException e) {
			state = CommunicationState.ERROR;
			throw new CommunicationException("An error occured while trying to open server port " + port, e);
		}
	}

	/* (non-Javadoc)
	 * @see se.cirrus.base.com.Listener#close()
	 */
	@Override
	public void close() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see se.cirrus.base.com.Listener#changePort(int)
	 */
	@Override
	public void changePort(int port) throws InvalidStateException {

		if(state == CommunicationState.CONNECTING || state == CommunicationState.NEGOTIATING ||
				state == CommunicationState.OPEN) {
			throw new InvalidStateException("Tried to change port on listener, but listener is in an " +
				"incorrect state for this.");
		}
		this.port = port;
	}

	/* (non-Javadoc)
	 * @see se.cirrus.base.com.Listener#getPort()
	 */
	@Override
	public int getPort() {

		return port;
	}
	
	
	public void run() {
		Socket s;
		
		log.fine("Listening thread started: " + this + " - now listening actively for new connections!");
		
		while(true) {
			try {
				s = socket.accept();
				log.fine("Connection opened: " + s.getLocalAddress().getHostName());
			} catch (IOException e) {
				// 	TODO Auto-generated catch block
				e.printStackTrace();
				s = null;
			}
		
			log.fine("Forwarding connection to controller.");
			controller.newConnectionAccepted(s);
		}
	}

}
